Page({
  data: {
    /** 图片路径 */
    imgSrc: '',
    /** 裁剪框高度 */
    height: 200,
    /** 裁剪框宽度 */
    width: 200,
    /** 裁剪框最小宽度 */
    min_width: 100,
    /** 裁剪框最小高度 */
    min_height: 100,
    /** 裁剪框最大宽度 */
    max_width: 300,
    /** 裁剪框最大高度 */
    max_height: 300,
    /** 是否禁止改变裁剪框宽度 */
    disable_width: false,
    /** 是否禁止改变裁剪框高度 */
    disable_height: false,
    /** 是否锁定裁剪框比例 */
    disable_ratio: false,
    /** 生成图片相对于裁剪框的缩放倍数 */
    export_scale: 3,
    /** 生成图片质量（0-1） */
    quality: 1,
    /** 裁剪框距离顶部的初始位置（未设置则居中） */
    cut_top: null,
    /** 裁剪框距离左侧的初始位置（未设置则居中） */
    cut_left: null,
    /** 画布容器距离顶部的定位（不设置则默认隐藏画布） */
    canvas_top: null,
    /** 画布容器距离左侧的定位（不设置则默认隐藏画布） */
    canvas_left: null,
    /** 原图宽度 */
    img_width: null,
    /** 原图高度 */
    img_height: null,
    /** 原图缩放比例 */
    scale: 1,
    /** 原图旋转角度 */
    angle: 0,
    /** 最小缩放倍数 */
    min_scale: 0.5,
    /** 最大缩放倍数 */
    max_scale: 2,
    /** 是否禁用旋转 */
    disable_rotate: false,
    /** 是否限制裁剪框在图片内移动 */
    limit_move: false,

    // 内部数据
    el: 'image-cropper', // 画布组件的ID
    info: {}, // 系统信息
    MOVE_THROTTLE: null, // 触摸移动节流定时器
    MOVE_THROTTLE_FLAG: true, // 触摸移动节流开关
    INIT_IMGWIDTH: 0, // 初始设置的目标图片宽度
    INIT_IMGHEIGHT: 0, // 初始设置的目标图片高度
    TIME_BG: null, // 背景变暗延时函数
    TIME_CUT_CENTER: null, // 裁剪框居中延时函数
    _touch_img_relative: [{ x: 0, y: 0 }], // 手指与图片中心的相对位置
    _flag_cut_touch: false, // 是否正在拖动裁剪框
    _hypotenuse_length: 0, // 双指触摸时的斜边长度
    _flag_img_endtouch: false, // 标记是否结束触摸
    _flag_bright: true, // 背景是否亮（裁剪框外区域）
    _canvas_overflow: true, // 隐藏画布是否在屏幕外
    _canvas_width: 200, // 画布宽度（初始为裁剪框宽度）
    _canvas_height: 200, // 画布高度（初始为裁剪框高度）
    origin_x: 0.5, // 图片旋转中心X（相对图片宽度比例）
    origin_y: 0.5, // 图片旋转中心Y（相对图片高度比例）
    _cut_animation: false, // 图片和裁剪框过渡动画开关
    _cut_animation_time: null, // 过渡动画计时器
    _img_top: wx.getSystemInfoSync().windowHeight / 2, // 图片初始上边距（居中显示）
    _img_left: wx.getSystemInfoSync().windowWidth / 2, // 图片初始左边距（居中显示）
    imageObject: null, // 图片信息对象（wx.getImageInfo 返回）
    // 数据字段监听器
    watch: {
      // 监听裁剪框宽度变化
      width(value, that) {
        if (value < that.data.min_width) {
          that.setData({ width: that.data.min_width });
        }
        that._computeCutSize();
      },
      // 监听裁剪框高度变化
      height(value, that) {
        if (value < that.data.min_height) {
          that.setData({ height: that.data.min_height });
        }
        that._computeCutSize();
      },
      // 监听旋转角度变化
      angle(value, that) {
        // 停止居中裁剪框，继续修改图片位置
        that._moveStop();
        if (that.data.limit_move) {
          if (that.data.angle % 90) {
            that.setData({ angle: Math.round(that.data.angle / 90) * 90 });
            return;
          }
        }
      },
      // 监听过渡动画开关变化
      _cut_animation(value, that) {
        // 开启过渡动画300毫秒后自动关闭
        clearTimeout(that.data._cut_animation_time);
        if (value) {
          that.data._cut_animation_time = setTimeout(() => {
            that.setData({ _cut_animation: false });
          }, 300);
        }
      },
      // 监听是否限制移动变化
      limit_move(value, that) {
        if (value) {
          if (that.data.angle % 90) {
            that.setData({ angle: Math.round(that.data.angle / 90) * 90 });
            return;
          }
        }
        that._imgMarginDetectionScale();
        !that.data._canvas_overflow && that._draw();
      },
      // 监听画布容器 top 值变化
      canvas_top(value, that) {
        that._canvasDetectionPosition();
      },
      // 监听画布容器 left 值变化
      canvas_left(value, that) {
        that._canvasDetectionPosition();
      },
      // 监听图片路径变化
      imgSrc(value, that) {
        that.pushImg();
      },
      // 监听裁剪框 top 值变化
      cut_top(value, that) {
        that._cutDetectionPosition();
        if (that.data.limit_move) {
          !that.data._canvas_overflow && that._draw();
        }
      },
      // 监听裁剪框 left 值变化
      cut_left(value, that) {
        that._cutDetectionPosition();
        if (that.data.limit_move) {
          !that.data._canvas_overflow && that._draw();
        }
      }
    }
  },

  // 页面加载时初始化
  onLoad(options) {
    // 从缓存获取待裁剪图片路径并设置
    const imgPath = wx.getStorageSync('tempCropPath');
    if (imgPath) {
      this.setData({ imgSrc: imgPath });
    }
    // 获取系统信息
    this.data.info = wx.getSystemInfoSync();
    // 启用数据监听
    this._watcher();
    // 记录初始图片目标尺寸
    this.data.INIT_IMGWIDTH = this.data.img_width;
    this.data.INIT_IMGHEIGHT = this.data.img_height;
    // 初始化隐藏画布尺寸为裁剪框尺寸
    this.setData({
      _canvas_width: this.data.width,
      _canvas_height: this.data.height
    });
    // 创建画布上下文
    this._initCanvas();
    // 如果有初始图片路径，触发图片加载
    if (this.data.imgSrc) {
      // 赋值自身以触发 watch.imgSrc
      this.data.imgSrc = this.data.imgSrc;
    }
    // 初始化图片尺寸参数
    this._initImageSize();
    // 修正裁剪框尺寸，防止超出屏幕
    this._computeCutSize();
    // 检查裁剪框位置有效性（未指定则居中）
    this._cutDetectionPosition();
    // 检查隐藏画布位置（默认移出屏幕外）
    this._canvasDetectionPosition();
  },

  // 取消裁剪，返回上一页
  cancelCrop() {
    wx.navigateBack();
  },

  // 完成裁剪，导出图片并返回
  finishCrop() {
    // 将当前裁剪区域绘制到隐藏画布并导出图片
    this._draw(() => {
      wx.canvasToTempFilePath({
        width: this.data.width * this.data.export_scale,
        height: Math.round(this.data.height * this.data.export_scale),
        destWidth: this.data.width * this.data.export_scale,
        destHeight: Math.round(this.data.height * this.data.export_scale),
        fileType: 'png',
        quality: this.data.quality,
        canvasId: this.data.el,
        success: (res) => {
          const path = res.tempFilePath;
          // 通过 eventChannel 将结果发送给上一个页面
          const eventChannel = this.getOpenerEventChannel ? this.getOpenerEventChannel() : null;
          if (eventChannel) {
            eventChannel.emit('cropDone', { path });
          }
          // 返回上一页
          wx.navigateBack();
        },
        fail: (err) => {
          console.error('canvasToTempFilePath 失败：', err);
          wx.showToast({ title: '裁剪失败', icon: 'none' });
        }
      });
    });
  },

  /**
   * 上传图片（替换当前裁剪图片）
   */
  upload() {
    let that = this;
    wx.chooseImage({
      count: 1,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        const tempFilePath = res.tempFilePaths[0];
        that.pushImg(tempFilePath);
        wx.showLoading({ title: '加载中...' });
      },
      fail() {
        wx.showToast({ title: '未选择图片', icon: 'none' });
      }
    });
  },

  /**
   * 获取裁剪后的图片信息
   */
  getImg(getCallback) {
    // 将当前画面绘制到隐藏画布，再导出图片临时路径
    this._draw(() => {
      wx.canvasToTempFilePath({
        width: this.data.width * this.data.export_scale,
        height: Math.round(this.data.height * this.data.export_scale),
        destWidth: this.data.width * this.data.export_scale,
        destHeight: Math.round(this.data.height * this.data.export_scale),
        fileType: 'png',
        quality: this.data.quality,
        canvasId: this.data.el,
        success: (res) => {
          // 返回裁剪后的图片信息
          getCallback({
            url: res.tempFilePath,
            width: this.data.width * this.data.export_scale,
            height: this.data.height * this.data.export_scale
          });
        },
        fail: (err) => {
          console.error('canvasToTempFilePath 失败：', err);
          wx.showToast({ title: '裁剪失败', icon: 'none' });
        }
      });
    });
  },

  /**
   * 设置图片变换
   * transform = { x, y, angle, scale }
   * x: 水平位移，y: 垂直位移
   * angle: 增加的旋转角度，scale: 增加的缩放倍数
   */
  setTransform(transform) {
    if (!transform) return;
    if (!this.data.disable_rotate) {
      this.setData({
        angle: transform.angle ? this.data.angle + transform.angle : this.data.angle
      });
    }
    let scale = this.data.scale;
    if (transform.scale) {
      scale = this.data.scale + transform.scale;
      scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
      scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
      this.setData({
        _cut_animation: true,
        scale: scale
      });
    }
    if (transform.x || transform.y) {
      this.setData({
        _img_top: this.data._img_top + (transform.y || 0),
        _img_left: this.data._img_left + (transform.x || 0)
      });
    }
    !this.data._canvas_overflow && this._draw();
  },

  /**
   * 设置裁剪框尺寸
   */
  setCutSize(w, h) {
    this.setData({
      width: w,
      height: h
    });
    this._computeCutSize();
  },

  /**
   * 裁剪框和图片居中
   */
  setCutCenter() {
    let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
    let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
    // 顺序不能变，先调整图片位置再设置裁剪框位置
    this.setData({
      _img_top: this.data._img_top - this.data.cut_top + cut_top,
      _img_left: this.data._img_left - this.data.cut_left + cut_left,
      cut_top: cut_top,
      cut_left: cut_left
    });
  },

  /**
   * 裁剪框居中（仅调整裁剪框位置，不移动图片）
   */
  _setCutCenter() {
    let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
    let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
    this.setData({
      cut_top: cut_top,
      cut_left: cut_left
    });
  },

  /**
   * 设置裁剪框宽度（即将废弃）
   */
  setWidth(width) {
    this.setData({ width: width });
    this._computeCutSize();
  },

  /**
   * 设置裁剪框高度（即将废弃）
   */
  setHeight(height) {
    this.setData({ height: height });
    this._computeCutSize();
  },

  /**
   * 是否禁用旋转
   */
  setDisableRotate(value) {
    this.data.disable_rotate = value;
  },

  /**
   * 是否限制移动范围
   */
  setLimitMove(value) {
    this.setData({
      _cut_animation: true,
      limit_move: !!value
    });
  },

  /**
   * 重置图片（缩放比和旋转角度重置，图片位置居中）
   */
  imgReset() {
    this.setData({
      scale: 1,
      angle: 0,
      _img_top: wx.getSystemInfoSync().windowHeight / 2,
      _img_left: wx.getSystemInfoSync().windowWidth / 2
    });
  },

  /**
   * 加载（或更换）图片
   */
  pushImg(src) {
    if (src) {
      this.setData({ imgSrc: src });
      // 手动赋值后直接返回，交由 watch.imgSrc 处理后续加载
      return;
    }
    if (!this.data.imgSrc) return;
    wx.getImageInfo({
      src: this.data.imgSrc,
      success: (res) => {
        this.data.imageObject = res;
        // 若图片非本地路径，则使用本地路径
        if (this.data.imgSrc.indexOf('tmp') === -1) {
          this.setData({ imgSrc: res.path });
        }
        // 计算原图最终显示尺寸
        this._imgComputeSize();
        if (this.data.limit_move) {
          // 限制移动时，处理图像边缘避免留白
          this._imgMarginDetectionScale();
        }
        // 绘制图片到隐藏画布
        this._draw();
        // 隐藏加载提示
        wx.hideLoading();
      },
      fail: (err) => {
        this.setData({ imgSrc: '' });
        wx.hideLoading();
      }
    });
  },

  /**
   * 图片加载完成（<image> bindload）
   */
  imageLoad(e) {
    // 略微延迟后隐藏加载提示（确保图片完全呈现）
    setTimeout(() => {
      wx.hideLoading();
    }, 500);
  },

  /**
   * 设置图片缩放
   */
  setScale(scale) {
    if (!scale) return;
    this.setData({ scale: scale });
    !this.data._canvas_overflow && this._draw();
  },

  /**
   * 设置图片旋转角度
   */
  setAngle(angle) {
    if (!angle) return;
    this.setData({
      _cut_animation: true,
      angle: angle
    });
    this._imgMarginDetectionScale();
    !this.data._canvas_overflow && this._draw();
  },

  // 初始化画布
  _initCanvas() {
    if (!this.data.ctx) {
      this.data.ctx = wx.createCanvasContext('image-cropper', this);
    }
  },

  /**
   * 根据目标宽高（可能是百分比字符串）计算实际图片尺寸
   */
  _initImageSize() {
    // 处理宽度为百分比的情况
    if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH === 'string' && this.data.INIT_IMGWIDTH.indexOf('%') !== -1) {
      let widthPercent = this.data.INIT_IMGWIDTH.replace('%', '');
      this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * parseFloat(widthPercent);
    }
    // 处理高度为百分比的情况
    if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT === 'string' && this.data.INIT_IMGHEIGHT.indexOf('%') !== -1) {
      let heightPercent = this.data.INIT_IMGHEIGHT.replace('%', '');
      this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * parseFloat(heightPercent);
    }
  },

  /**
   * 检测裁剪框位置是否在允许范围内（屏幕内）
   * 如果未设置初始位置则默认居中
   */
  _cutDetectionPosition() {
    let _cutDetectionPositionTop = () => {
      // 检测裁剪框顶部边界
      if (this.data.cut_top < 0) {
        this.setData({ cut_top: 0 });
      }
      if (this.data.cut_top > this.data.info.windowHeight - this.data.height) {
        this.setData({ cut_top: this.data.info.windowHeight - this.data.height });
      }
    };
    let _cutDetectionPositionLeft = () => {
      // 检测裁剪框左侧边界
      if (this.data.cut_left < 0) {
        this.setData({ cut_left: 0 });
      }
      if (this.data.cut_left > this.data.info.windowWidth - this.data.width) {
        this.setData({ cut_left: this.data.info.windowWidth - this.data.width });
      }
    };
    // 裁剪框坐标处理
    if (this.data.cut_top == null && this.data.cut_left == null) {
      // 未设置顶部和左侧，则裁剪框居中
      this._setCutCenter();
    } else if (this.data.cut_top != null && this.data.cut_left != null) {
      // 均已设置，检查边界
      _cutDetectionPositionTop();
      _cutDetectionPositionLeft();
    } else if (this.data.cut_top != null && this.data.cut_left == null) {
      // 仅设置顶部，水平居中
      _cutDetectionPositionTop();
      this.setData({
        cut_left: (this.data.info.windowWidth - this.data.width) / 2
      });
    } else if (this.data.cut_top == null && this.data.cut_left != null) {
      // 仅设置左侧，垂直居中
      _cutDetectionPositionLeft();
      this.setData({
        cut_top: (this.data.info.windowHeight - this.data.height) / 2
      });
    }
  },

  /**
   * 检测隐藏画布位置是否在允许范围内（屏幕内）
   * 如果隐藏画布位于屏幕外则不实时绘制，提高性能
   * 如果未设置位置则默认放在屏幕外
   */
  _canvasDetectionPosition() {
    if (this.data.canvas_top == null && this.data.canvas_left == null) {
      // 未指定画布位置，默认移出屏幕外但保持实时绘制
      this.data._canvas_overflow = false;
      this.setData({
        canvas_top: -5000,
        canvas_left: -5000
      });
    } else if (this.data.canvas_top != null && this.data.canvas_left != null) {
      if (this.data.canvas_top < -this.data.height || this.data.canvas_top > this.data.info.windowHeight) {
        this.data._canvas_overflow = true;
      } else {
        this.data._canvas_overflow = false;
      }
    } else if (this.data.canvas_top != null && this.data.canvas_left == null) {
      this.setData({ canvas_left: 0 });
    } else if (this.data.canvas_top == null && this.data.canvas_left != null) {
      this.setData({ canvas_top: 0 });
      if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) {
        this.data._canvas_overflow = true;
      } else {
        this.data._canvas_overflow = false;
      }
    }
  },

  /**
   * 图像边缘检测 - 位置校正
   * 确保裁剪框限制移动时，图片始终覆盖裁剪区域
   */
  _imgMarginDetectionPosition(scale) {
    if (!this.data.limit_move) return;
    let left = this.data._img_left;
    let top = this.data._img_top;
    scale = scale || this.data.scale;
    let img_width = this.data.img_width;
    let img_height = this.data.img_height;
    // 若图片旋转90度，则交换宽高
    if (this.data.angle / 90 % 2) {
      img_width = this.data.img_height;
      img_height = this.data.img_width;
    }
    // 限制图片不得小于裁剪框尺寸
    left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2;
    left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : (this.data.cut_left + this.data.width - img_width * scale / 2);
    top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2;
    top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : (this.data.cut_top + this.data.height - img_height * scale / 2);
    this.setData({
      _img_left: left,
      _img_top: top,
      scale: scale
    });
  },

  /**
   * 图像边缘检测 - 缩放校正
   * 确保裁剪框限制移动时，图片缩放后仍覆盖裁剪区域
   */
  _imgMarginDetectionScale() {
    if (!this.data.limit_move) return;
    let scale = this.data.scale;
    let img_width = this.data.img_width;
    let img_height = this.data.img_height;
    // 若图片旋转90度，则交换宽高
    if (this.data.angle / 90 % 2) {
      img_width = this.data.img_height;
      img_height = this.data.img_width;
    }
    // 限制图片缩放不得小于裁剪框对应边长
    if (img_width * scale < this.data.width) {
      scale = this.data.width / img_width;
    }
    if (img_height * scale < this.data.height) {
      scale = Math.max(scale, this.data.height / img_height);
    }
    this._imgMarginDetectionPosition(scale);
  },

  /**
   * 设置数据（仅设置有变化的字段）
   */
  _setData(obj) {
    let data = {};
    for (let key in obj) {
      if (this.data[key] !== obj[key]) {
        data[key] = obj[key];
      }
    }
    this.setData(data);
    return data;
  },

  /**
   * 计算图片最终显示尺寸（自适应裁剪框）
   */
  _imgComputeSize() {
    let img_width = this.data.img_width;
    let img_height = this.data.img_height;
    // 如果未指定目标宽高，默认使图片的较小边等于裁剪框对应边
    if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
      img_width = this.data.imageObject.width;
      img_height = this.data.imageObject.height;
      if (img_width / img_height > this.data.width / this.data.height) {
        // 宽高比大于裁剪框，则以裁剪框高度为基准
        img_height = this.data.height;
        img_width = this.data.imageObject.width / this.data.imageObject.height * img_height;
      } else {
        // 宽高比小于等于裁剪框，则以裁剪框宽度为基准
        img_width = this.data.width;
        img_height = this.data.imageObject.height / this.data.imageObject.width * img_width;
      }
    } else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
      // 指定高度，按高度缩放宽度
      img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT;
    } else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) {
      // 指定宽度，按宽度缩放高度
      img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH;
    }
    this.setData({
      img_width: img_width,
      img_height: img_height
    });
  },

  /**
   * 修正裁剪框尺寸，防止其超出屏幕范围
   */
  _computeCutSize() {
    if (this.data.width > this.data.info.windowWidth) {
      this.setData({ width: this.data.info.windowWidth });
    } else if (this.data.width + this.data.cut_left > this.data.info.windowWidth) {
      this.setData({ cut_left: this.data.info.windowWidth - this.data.cut_left });
    }
    if (this.data.height > this.data.info.windowHeight) {
      this.setData({ height: this.data.info.windowHeight });
    } else if (this.data.height + this.data.cut_top > this.data.info.windowHeight) {
      this.setData({ cut_top: this.data.info.windowHeight - this.data.cut_top });
    }
    !this.data._canvas_overflow && this._draw();
  },

  // 手指触摸开始
  _start(event) {
    this.data._flag_img_endtouch = false;
    if (event.touches.length === 1) {
      // 单指拖动，记录初始相对位置
      this.data._touch_img_relative[0] = {
        x: event.touches[0].clientX - this.data._img_left,
        y: event.touches[0].clientY - this.data._img_top
      };
    } else {
      // 双指缩放，记录初始两指相对位置和距离
      let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
      let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);
      this.data._touch_img_relative = [
        {
          x: event.touches[0].clientX - this.data._img_left,
          y: event.touches[0].clientY - this.data._img_top
        },
        {
          x: event.touches[1].clientX - this.data._img_left,
          y: event.touches[1].clientY - this.data._img_top
        }
      ];
      this.data._hypotenuse_length = Math.sqrt(width * width + height * height);
    }
    !this.data._canvas_overflow && this._draw();
  },

  // 触摸移动节流（降低安卓系统频繁触发次数）
  _move_throttle() {
    if (this.data.info.platform === 'android') {
      clearTimeout(this.data.MOVE_THROTTLE);
      this.data.MOVE_THROTTLE = setTimeout(() => {
        this.data.MOVE_THROTTLE_FLAG = true;
      }, 1000 / 40);
      return this.data.MOVE_THROTTLE_FLAG;
    } else {
      this.data.MOVE_THROTTLE_FLAG = true;
    }
  },

  // 手指触摸移动
  _move(event) {
    if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return;
    this.data.MOVE_THROTTLE_FLAG = false;
    this._move_throttle();
    this._moveDuring();
    if (event.touches.length === 1) {
      // 单指拖动
      let left = event.touches[0].clientX - this.data._touch_img_relative[0].x;
      let top = event.touches[0].clientY - this.data._touch_img_relative[0].y;
      // 图像边缘检测，防止出现裁剪空白
      this.data._img_left = left;
      this.data._img_top = top;
      this._imgMarginDetectionPosition();
      this.setData({
        _img_left: this.data._img_left,
        _img_top: this.data._img_top
      });
    } else {
      // 双指缩放/旋转
      let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
      let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);
      let hypotenuse = Math.sqrt(width * width + height * height);
      let scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length);
      let current_deg = 0;
      // 限制缩放范围
      scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
      scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
      // 更新 scale 并边缘检测
      this.data.scale = scale;
      this._imgMarginDetectionScale();
      // 计算旋转角度增量（若未禁用旋转）
      let _touch_img_relative = [
        {
          x: event.touches[0].clientX - this.data._img_left,
          y: event.touches[0].clientY - this.data._img_top
        },
        {
          x: event.touches[1].clientX - this.data._img_left,
          y: event.touches[1].clientY - this.data._img_top
        }
      ];
      if (!this.data.disable_rotate) {
        let first_atan = (180 / Math.PI) * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x);
        let first_atan_old = (180 / Math.PI) * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x);
        let second_atan = (180 / Math.PI) * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x);
        let second_atan_old = (180 / Math.PI) * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x);
        // 当前旋转角度（取第一个不为0的变化量）
        let first_deg = first_atan - first_atan_old;
        let second_deg = second_atan - second_atan_old;
        if (first_deg !== 0) {
          current_deg = first_deg;
        } else if (second_deg !== 0) {
          current_deg = second_deg;
        }
      }
      // 更新触摸参考数据
      this.data._touch_img_relative = _touch_img_relative;
      this.data._hypotenuse_length = Math.sqrt(width * width + height * height);
      // 更新旋转角度和缩放至视图
      this.setData({
        angle: this.data.angle + current_deg,
        scale: this.data.scale
      });
    }
    !this.data._canvas_overflow && this._draw();
  },

  // 手指触摸结束
  _end(event) {
    this.data._flag_img_endtouch = true;
    this._moveStop();
  },

  // 点击裁剪区域（空白区）处理
  _click(event) {
    if (!this.data.imgSrc) {
      // 未选择图片则调起上传
      this.upload();
      return;
    }
    this._draw(() => {
      // 触摸点坐标
      let x = event.detail ? event.detail.x : event.touches[0].clientX;
      let y = event.detail ? event.detail.y : event.touches[0].clientY;
      // 判断触摸点是否在裁剪框内
      if (
        x >= this.data.cut_left &&
        x <= this.data.cut_left + this.data.width &&
        y >= this.data.cut_top &&
        y <= this.data.cut_top + this.data.height
      ) {
        // 在裁剪框内，则导出图片并返回上一页
        wx.canvasToTempFilePath({
          width: this.data.width * this.data.export_scale,
          height: Math.round(this.data.height * this.data.export_scale),
          destWidth: this.data.width * this.data.export_scale,
          destHeight: Math.round(this.data.height * this.data.export_scale),
          fileType: 'png',
          quality: this.data.quality,
          canvasId: this.data.el,
          success: (res) => {
            const eventChannel = this.getOpenerEventChannel ? this.getOpenerEventChannel() : null;
            if (eventChannel) {
              eventChannel.emit('cropDone', { path: res.tempFilePath });
            }
            wx.navigateBack();
          },
          fail: (err) => {
            console.error('canvasToTempFilePath 失败：', err);
            wx.showToast({ title: '裁剪失败', icon: 'none' });
          }
        });
      }
    });
  },

  // 将图片绘制到隐藏画布（用于导出）
  _draw(callback) {
    if (!this.data.imgSrc) return;
    // 绘制函数
    const draw = () => {
      // 计算绘制尺寸（考虑缩放倍数）
      let img_width = this.data.img_width * this.data.scale * this.data.export_scale;
      let img_height = this.data.img_height * this.data.scale * this.data.export_scale;
      // 计算画布与裁剪框的相对位移
      let xpos = this.data._img_left - this.data.cut_left;
      let ypos = this.data._img_top - this.data.cut_top;
      // 平移原点并旋转画布
      this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale);
      this.data.ctx.rotate((this.data.angle * Math.PI) / 180);
      // 绘制图片到画布
      this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height);
      this.data.ctx.draw(false, () => {
        callback && callback();
      });
    };
    if (this.data.ctx.width !== this.data.width || this.data.ctx.height !== this.data.height) {
      // 如果画布尺寸与裁剪框尺寸不一致，先调整画布尺寸，再进行绘制
      this.setData(
        {
          _canvas_height: this.data.height,
          _canvas_width: this.data.width
        },
        () => {
          // 延迟40ms，避免过快点击导致绘制异常
          setTimeout(() => {
            draw();
          }, 40);
        }
      );
    } else {
      draw();
    }
  },

  // 裁剪框拖动 - 手指移动中
  _cutTouchMove(e) {
    if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) {
      if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return;
      // 节流
      this.data.MOVE_THROTTLE_FLAG = false;
      this._move_throttle();
      let width = this.data.width;
      let height = this.data.height;
      let cut_top = this.data.cut_top;
      let cut_left = this.data.cut_left;
      // 尺寸修正函数
      const size_correct = () => {
        width = width <= this.data.max_width ? (width >= this.data.min_width ? width : this.data.min_width) : this.data.max_width;
        height = height <= this.data.max_height ? (height >= this.data.min_height ? height : this.data.min_height) : this.data.max_height;
      };
      // 尺寸有效性检查函数
      const size_inspect = () => {
        if (
          (width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) &&
          this.data.disable_ratio
        ) {
          size_correct();
          return false;
        } else {
          size_correct();
          return true;
        }
      };
      // 根据拖动的角标方向计算新的宽高
      height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY));
      switch (this.data.CUT_START.corner) {
        case 1:
          width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
          if (this.data.disable_ratio) {
            height = width / (this.data.width / this.data.height);
          }
          if (!size_inspect()) return;
          cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);
          break;
        case 2:
          width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
          if (this.data.disable_ratio) {
            height = width / (this.data.width / this.data.height);
          }
          if (!size_inspect()) return;
          cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);
          cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);
          break;
        case 3:
          width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
          if (this.data.disable_ratio) {
            height = width / (this.data.width / this.data.height);
          }
          if (!size_inspect()) return;
          cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);
          break;
        case 4:
          width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
          if (this.data.disable_ratio) {
            height = width / (this.data.width / this.data.height);
          }
          if (!size_inspect()) return;
          break;
      }
      // 根据禁用情况设置新的裁剪框尺寸和位置
      if (!this.data.disable_width && !this.data.disable_height) {
        this.setData({
          width: width,
          cut_left: cut_left,
          height: height,
          cut_top: cut_top
        });
      } else if (!this.data.disable_width) {
        this.setData({
          width: width,
          cut_left: cut_left
        });
      } else if (!this.data.disable_height) {
        this.setData({
          height: height,
          cut_top: cut_top
        });
      }
      // 限制图片边缘，防止裁剪框范围外出现空白
      this._imgMarginDetectionScale();
    }
  },

  // 裁剪框触摸开始（判断拖动哪个角或边）
  _cutTouchStart(e) {
    let currentX = e.touches[0].clientX;
    let currentY = e.touches[0].clientY;
    // 四个角的热区坐标范围计算（扩大30px感应区）
    let cutbox_top4 = this.data.cut_top + this.data.height - 30;
    let cutbox_bottom4 = this.data.cut_top + this.data.height + 20;
    let cutbox_left4 = this.data.cut_left + this.data.width - 30;
    let cutbox_right4 = this.data.cut_left + this.data.width + 30;
    let cutbox_top3 = this.data.cut_top - 30;
    let cutbox_bottom3 = this.data.cut_top + 30;
    let cutbox_left3 = this.data.cut_left + this.data.width - 30;
    let cutbox_right3 = this.data.cut_left + this.data.width + 30;
    let cutbox_top2 = this.data.cut_top - 30;
    let cutbox_bottom2 = this.data.cut_top + 30;
    let cutbox_left2 = this.data.cut_left - 30;
    let cutbox_right2 = this.data.cut_left + 30;
    let cutbox_top1 = this.data.cut_top + this.data.height - 30;
    let cutbox_bottom1 = this.data.cut_top + this.data.height + 30;
    let cutbox_left1 = this.data.cut_left - 30;
    let cutbox_right1 = this.data.cut_left + 30;
    // 判断触摸点位于哪个角的范围内
    if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {
      // 右下角
      this._moveDuring();
      this.data._flag_cut_touch = true;
      this.data._flag_img_endtouch = true;
      this.data.CUT_START = {
        width: this.data.width,
        height: this.data.height,
        x: currentX,
        y: currentY,
        corner: 4
      };
    } else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {
      // 右上角
      this._moveDuring();
      this.data._flag_cut_touch = true;
      this.data._flag_img_endtouch = true;
      this.data.CUT_START = {
        width: this.data.width,
        height: this.data.height,
        x: currentX,
        y: currentY,
        cut_top: this.data.cut_top,
        cut_left: this.data.cut_left,
        corner: 3
      };
    } else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {
      // 左上角
      this._moveDuring();
      this.data._flag_cut_touch = true;
      this.data._flag_img_endtouch = true;
      this.data.CUT_START = {
        width: this.data.width,
        height: this.data.height,
        cut_top: this.data.cut_top,
        cut_left: this.data.cut_left,
        x: currentX,
        y: currentY,
        corner: 2
      };
    } else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {
      // 左下角
      this._moveDuring();
      this.data._flag_cut_touch = true;
      this.data._flag_img_endtouch = true;
      this.data.CUT_START = {
        width: this.data.width,
        height: this.data.height,
        cut_top: this.data.cut_top,
        cut_left: this.data.cut_left,
        x: currentX,
        y: currentY,
        corner: 1
      };
    }
  },

  // 裁剪框触摸结束
  _cutTouchEnd(e) {
    this._moveStop();
    this.data._flag_cut_touch = false;
  },

  // 停止移动（手指离开或停止拖动）时的处理
  _moveStop() {
    // 清除之前的自动居中延时，并启动新的延时
    clearTimeout(this.data.TIME_CUT_CENTER);
    this.data.TIME_CUT_CENTER = setTimeout(() => {
      // 若未开启过渡动画，启动之
      if (!this.data._cut_animation) {
        this.setData({ _cut_animation: true });
      }
      // 使裁剪框和图片居中
      this.setCutCenter();
    }, 1000);
    // 清除之前的背景变化延时，并启动新的延时
    clearTimeout(this.data.TIME_BG);
    this.data.TIME_BG = setTimeout(() => {
      if (this.data._flag_bright) {
        this.setData({ _flag_bright: false });
      }
    }, 2000);
  },

  // 手指移动过程中（节流中重复调用）
  _moveDuring() {
    // 清除之前的自动居中延时
    clearTimeout(this.data.TIME_CUT_CENTER);
    // 清除之前的背景变化延时
    clearTimeout(this.data.TIME_BG);
    // 高亮裁剪框外背景
    if (!this.data._flag_bright) {
      this.setData({ _flag_bright: true });
    }
  },

  // 启用数据监听
  _watcher() {
    Object.keys(this.data).forEach((v) => {
      this._observe(this.data, v, this.data.watch[v]);
    });
  },

  // 定义响应式数据
  _observe(obj, key, watchFun) {
    let val = obj[key];
    Object.defineProperty(obj, key, {
      configurable: true,
      enumerable: true,
      set: (value) => {
        val = value;
        watchFun && watchFun(val, this);
      },
      get() {
        if (
          val &&
          '_img_top|_img_left|width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key) !== -1
        ) {
          let ret = parseFloat(parseFloat(val).toFixed(3));
          if (typeof val === 'string' && val.indexOf('%') !== -1) {
            ret += '%';
          }
          return ret;
        }
        return val;
      }
    });
  },

  // 防止触摸穿透（用于catchtouchmove）
  _preventTouchMove() {}
});
